/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.rpc.client.listener;

import io.iec.edp.caf.commons.core.SerializerFactory;
import io.iec.edp.caf.commons.core.enums.SerializeType;
import io.iec.edp.caf.commons.utils.StringUtils;
//import io.iec.edp.caf.core.context.ICAFContextService;
import io.iec.edp.caf.logging.CommonConstant;
import io.iec.edp.caf.logging.TraceIdGenerator;
import io.iec.edp.caf.rpc.api.event.*;
import io.iec.edp.caf.rpc.api.support.ConstanceVarible;
import io.iec.edp.caf.rpc.api.spi.RpcContextResolver;
import io.iec.edp.caf.rpc.api.spi.RpcContextTransmittee;
import lombok.var;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;

public class RpcClientLoggingListener implements IRpcClientEventListener {

    private final String START_TIME = "startTime";
    private final Logger logger = LoggerFactory.getLogger(RpcClientLoggingListener.class);
//    private ICAFContextService cafContextService;

    @Override
    public void preInvokeEvent(PreRpcInvokeEventArgs args) {
        Map<String, Object> localContext = args.getLocalContext();
        Map<String, String> context = args.getContext();

        //传递或生成traceId 并放入localDict
        String traceId = MDC.get(CommonConstant.LOG_TRACE_ID);
        if (StringUtils.isEmpty(traceId)) {
            traceId = TraceIdGenerator.generate();
            MDC.put(CommonConstant.LOG_TRACE_ID, traceId);
        }

        String msu = MDC.get(CommonConstant.LOG_MSU_ID);
        if (StringUtils.isEmpty(msu)) {
            var rpcContext = RpcContextResolver.capture(RpcContextTransmittee.TransmitteType.MSU.getValue());
            msu = rpcContext!=null?(String) rpcContext.getContext("transmitte-msu"):"";
            if (!StringUtils.isEmpty(msu)) {
                MDC.put(CommonConstant.LOG_MSU_ID, msu);
            }
        }

        localContext.put(CommonConstant.LOG_TRACE_ID, traceId);

        long start = System.currentTimeMillis();
        localContext.put(START_TIME, start);

        String serviceId = context.get(ConstanceVarible.CURRENT_SERVICE_ID);
        String su = context.get(ConstanceVarible.TARGET_SU);
        String origin = "true".equals(context.get(ConstanceVarible.IS_LOCAL)) ? "local" : "remote";
        var serializer = SerializerFactory.getSerializer(SerializeType.Json);

        if (logger.isDebugEnabled()) {
            logger.debug("Start Rpc {} calling: serviceId is {},su is {}, param is {}", origin, serviceId,su, serializer.serializeToString(args.getParameters()));
        }else if (logger.isInfoEnabled()) {
            logger.info("Start Rpc {} calling: serviceId is {},su is {}", origin, serviceId,su);
        }
    }

    @Override
    //记录客户端请求成功日志
    public void postInvokeEvent(PostRpcInvokeEventArgs args) {
        Map<String, Object> localContext = args.getLocalContext();
        Map<String, String> context = args.getContext();
        long end = System.currentTimeMillis();
        Long cost = end - (long) localContext.get(START_TIME);

        String serviceId = context.get(ConstanceVarible.CURRENT_SERVICE_ID);
        String su = context.get(ConstanceVarible.TARGET_SU);
        String origin = "true".equals(context.get(ConstanceVarible.IS_LOCAL)) ? "local" : "remote";
        var serializer = SerializerFactory.getSerializer(SerializeType.Json);

        if (logger.isDebugEnabled()) {
            logger.debug("Finish Rpc {} calling: serviceId is {},su is {},cost {}ms, result is {}", origin, serviceId,su, cost, serializer.serializeToString(args.getMethodResult()));
        }else if(logger.isInfoEnabled()) {
            logger.info("Finish Rpc {} calling: serviceId is {},su is {},cost {}ms.", origin, serviceId,su, cost);
        }
    }

    @Override
    //记录客户端请求异常日志
    public void exceptionInvokeEvent(ExceptionRpcInvokeEventArgs args) {
        Map<String, String> context = args.getContext();
        Exception exception = args.getException();

        String serviceId = context.get(ConstanceVarible.CURRENT_SERVICE_ID);
        String su = context.get(ConstanceVarible.TARGET_SU);
        String origin = "true".equals(context.get(ConstanceVarible.IS_LOCAL)) ? "local" : "remote";

//        var msg = Base64.getEncoder().encode(getExceptionToString(exception).getBytes());
//        logger.error("Exception in Rpc {} calling: serviceId is {},su is {},exception is {}", origin, serviceId, su, getExceptionToString(exception));
        logger.error("Exception in Rpc {} calling: serviceId is {},su is {},exception is {}", origin, serviceId, su,getExceptionToString(exception));
    }

    /**
     * 从上下文中获取MSU
     *
     * @return
     */
//    public String getContextMsu() {
//        if (this.cafContextService == null) {
//            cafContextService = SpringBeanUtils.getBean(ICAFContextService.class);
//        }
//
//        if (cafContextService != null) {
//            return cafContextService.getCurrentSU();
//        }
//
//        return null;
//    }


    public String getExceptionToString(Throwable e) {
        if (e == null){
            return "";
        }
        StringWriter stringWriter = new StringWriter();
        e.printStackTrace(new PrintWriter(stringWriter));
        return stringWriter.toString();//replaceAll("\r\n","").replaceAll("\n","");
    }
}

